


#ifndef __QE_PACK_H__
#define __QE_PACK_H__



#include "qe_def.h"
#include "qe_array.h"
#include "qe_buffer.h"



#define qe_pack_align(n)                __attribute__ ((aligned (n)))

#define _qe_pack_bytes(data, p, bytes) do {\
					qe_memcpy(p, (char *)&data, bytes);\
					p+= bytes;\
				}while(0)
#define _qe_pack_stris(data, p, bytes) do {\
					qe_strncpy((char *)p, (char *)data, bytes);\
					p+= bytes;\
				}while(0)
#define qe_pack_byte(data, p) 				_qe_pack_bytes(data, p, 1)
#define qe_pack_word(data, p) 				_qe_pack_bytes(data, p, 2)
#define qe_pack_dwrd(data, p) 				_qe_pack_bytes(data, p, 4)
#define qe_pack_bytes(data, p, len) 		_qe_pack_bytes(data, p, len)
#define qe_pack_stris(data, p, len)			_qe_pack_stris(data, p, len)

#define _qe_pack_bytes_safe(data, p, bytes, end) do {\
					if ((end - p) >= bytes)\
						qe_memcpy(p, (unsigned char *)&data, bytes);\
					p+= bytes;\
				}while(0)
#define _qe_pack_stris_safe(data, p, bytes, end) do {\
					if ((end - p) >= bytes)\
						qe_strncpy(p, data, bytes);\
					p+= bytes;\
				}while(0)

#define qe_pack_byte_safe(data, p, end) 		_qe_pack_bytes_safe(data, p, 1, end)
#define qe_pack_word_safe(data, p, end) 		_qe_pack_bytes_safe(data, p, 2, end)
#define qe_pack_dwrd_safe(data, p, end) 		_qe_pack_bytes_safe(data, p, 4, end)
#define qe_pack_bytes_safe(data, p, end, ln)	_qe_pack_bytes_safe(data, p, ln, end)
#define qe_pack_stris_safe(data, p, end, ln)	_qe_pack_bytes_safe(data, p, ln, end)

#define _qe_unpack_bytes(data, p, bytes) do {\
		qe_memcpy((unsigned char *)&data, p, bytes);\
		p+= bytes;\
	}while(0)
#define _qe_unpack_stris(data, p, bytes) do {\
			qe_strncpy((char *)data, (char *)p, bytes);\
			p+= bytes;\
		}while(0)

#define qe_unpack_byte(data, p)			_qe_unpack_bytes(data, p, 1)
#define qe_unpack_word(data, p)			_qe_unpack_bytes(data, p, 2)
#define qe_unpack_dwrd(data, p)			_qe_unpack_bytes(data, p, 4)
#define qe_unpack_bytes(data, p, len)	_qe_unpack_bytes(data, p, len)
#define qe_unpack_stris(data, p, len)	_qe_unpack_stris(data, p, len)


typedef struct
{
	qe_u8 *s;
	qe_u8 *v;
	qe_u8 type;
	qe_u16 len;
} qe_sergp_tlv;

typedef struct
{
	qe_sergp_tlv tlv;
	qe_u8 sum;
	qe_gbuf *buf;
} qe_sergp;

#define qe_sergp_type(s)		((s)->tlv.type)
#define qe_sergp_length(s)		((s)->tlv.len)
#define qe_sergp_val_pos(s)		((s)->tlv.v)

qe_u8 qe_checksum_u8(char *buf, unsigned int len);
qe_u32 qe_checksum_u32(char *buf, unsigned int len);

/**
 * @brief BinaryPackage parse function
 * 
 * @param[in] hdr: header
 * @param[in] sectab_bytes: section table bytes pointer
 * @param[out] sections: sections array
 * 
 * @return qe_ret
 */
qe_ret qe_binpkg_parse(qe_binpkg_header *hdr, qe_u8 *sectab_bytes, qe_array *sections);

/**
 * @brief BinaryPackage get section table size
 * 
 * @param[in] hdr: header struct
 * 
 * @return table size
 */
qe_size qe_binpkg_get_sectab_size(qe_binpkg_header *hdr);

/**
 * @subpage PackBuffer
 */
typedef struct
{
	char *data;
	qe_size size;
	qe_size alloc;
} qe_pack_buffer;

qe_int 
qe_pack_buffer_write(qe_pack_buffer *buf, const char* data, qe_size len);

void
qe_pack_buffer_init(qe_pack_buffer *buf);

qe_pack_buffer *
qe_pack_buffer_new();

void 
qe_pack_buffer_destroy(qe_pack_buffer *buf);

/**
 * @brief Slip decode
 * 
 * @param[in] in: input buffer
 * @param[in] in_bytes: input buffer bytes
 * @param[out] out: output decoded buffer
 * @param[out] out_size: output decoded buffer size
 * 
 * @return <0:error >=0:decode size
 */
qe_int qe_slip_decode(qe_u8 *in, qe_size in_bytes, 
    qe_u8 *out, qe_size out_size);

/**
 * @brief Slip encode
 * @param[in] in: input buffer
 * @param[in] in_size: input buffer length
 * @param[out] out: output buffer
 * @param[out] out_size: output buffer length
 * 
 * @return <0:error >=0:encode size
 */
qe_int qe_slip_encode(qe_u8 *in, qe_size in_size, 
    qe_u8 *out, qe_size out_size);

/**
 * @brief Find a complete SLIP packet from the buffer
 * @param[in] buf: buffer to find
 * @param[in] size: buffer length
 * @param[out] len: find SLIP packet length
 * 
 * @return <0:error >=0:find size
 */
qe_int qe_slip_find(qe_u8 *buf, qe_size size, qe_size *len);

/**
 * @brief Find SLIP begin from the buffer
 * @param[in] buf: buffer to find
 * @param[in] size: buffer length
 * 
 * @return <0:error >=0:SLIP begin offset
 */
qe_int qe_slip_begin(qe_u8 *buf, qe_size size);

qe_ret qe_slip_pack(qe_pack_buffer *buf, qe_u8 *in, qe_size in_size);
qe_ret qe_slip_unpack(qe_pack_buffer *buf, qe_u8 *in, qe_size in_size);


/**
 * @brief SERGP package into a buffer
 * @param[in] type: TLV type
 * @param[in] data: package data
 * @param[in] len: TLV length
 * @param[out] out: SERGP buffer
 * @param[out] size: SERGP buffer size
 * 
 * @return <0:error >=0: package length
 */
qe_int qe_sergp_pack(qe_u8 *type, qe_u8 *data, qe_size len, 
    qe_u8 *out, qe_size size);

/**
 * @brief SERGP unpack from buffer into a <qe_sergp>
 * @param[in] buf: SERGP packet
 * @param[in] len: SERGP length
 * @param[out] s: unpack struct
 * 
 * @return <qe_ret>
 * 
 * @note This function need you alloc memory for <qe_sergp> before.
 * You can create by qe_sergp_new()
 */
qe_ret qe_sergp_unpack(qe_u8 *buf, qe_size len, qe_sergp *s);

/**
 * @brief Create a <qe_sergp> with give buffer size
 * @param[in] size: buffer size
 * 
 * @return: <qe_sergp>
 */
qe_sergp *qe_sergp_new(qe_size size);

/**
 * @brief Destroy a <qe_strgp>
 */
void qe_sergp_destroy(qe_sergp *s);

/**
 * @brief Unpack SERGP dump to <qe_sergp>
 * @param[in] buf: SERGP buffer
 * @param[in] len: SERGP length
 * 
 * @return <qe_sergp>
 */
qe_sergp *qe_sergp_unpack_dup(qe_u8 *buf, qe_size len);

#endif /* __QE_PACK_H__ */